<!doctype html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
	<!-- <meta http-equiv="refresh" content="1" > -->

    <title>SLAM实时地图</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        body {
            background: rgba(3, 3, 3, 0.199);
        }

        .box {
            background-color: darkseagreen;
            height: 80%;
            width: 100%;
        }

        .canvas_css {
            background-color: darkseagreen;
            float: left;
            /* height: 80%;
            width: 100%; */
            margin: auto;
        }

        .bt_css {
            background-color: rgb(245, 245, 220);
            float: right;
            /* height: 50%;
            width: 50%; */
            margin: auto;
        }
        .ul {
            display: flex;
            align-items: center;
            list-style: none;
            margin: 10px auto;
            float: left;
        }
        .ul > li {
            margin-right: 10px;
        }
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
        /* 多层画布 */
        .backgrounds {
            z-index: 0;
            -webkit-filter: blur(6px);
            filter: blur(6px);
            background-image: -webkit-radial-gradient(#4682b4, #191970);
            background-image: radial-gradient(#4682b4, #191970);
        }
        .back {
            z-index: 1;
            -webkit-filter: blur(6px);
            filter: blur(6px);
            background-image: -webkit-radial-gradient(#4682b4, #191970);
            background-image: radial-gradient(#4682b4, #191970);
        }
        .mid {
            z-index: 2;
            -webkit-filter: blur(3px);
            filter: blur(3px);
            mix-blend-mode: lighten;
            background: rgba(255, 255, 255, 0);
        }
        .front {
            z-index: 3;
            -webkit-filter: blur(1px);
            filter: blur(1px);
            mix-blend-mode: luminosity;
        }
    </style>
</head>

<body>
    <div class="box" id='content'>

        <div class="bt_css" id='content1'>
            <ul class="ul">
                <li><button onclick="on_start_slam()" id="startSlam"> 开始建图</button></li>
                <li><button onclick="on_save_slam()" id="saveSlam"> 保存地图</button> </li>
            </ul>
        </div>
        <canvas  class="canvas_css"  id='canvas' width=1900 height=900  style="border: 1px solid">
            您的浏览器版本过低，请更新浏览器
        </canvas>
        <canvas id="backgrounds"  width=1900 height=800></canvas>
        <canvas id="back"         width=1900 height=800></canvas>
        <canvas id="mid"          width=1900 height=800></canvas>
        <canvas id="front"        width=1900 height=800></canvas>
    </div>


    <script type="text/javascript">

        var g_offset = {
            x: 80,
            y: 80
        }

        var g_size = {
            x: 10,
            y: 10
        }

        var g_robot_position = {
            x: 0,
            y: 0,
            theta: 0
        }

        var g_map_data = "";
        var g_get_slam_data = null;
        var g_slam_flag = false;
        var g_timer_id = null;
        var g_get_slam_map_url = "/get_map_data?type=get_slam_data";
        var g_get_pointcloud_url = "/get_map_data?type=get_pointCloud";
        var g_get_robot_state_url = "/get_map_data?type=get_robotState";
        var g_get_using_map_url = "/get_map_data?type=get_using_map";
        var g_countryList = []
        let g_pointcloud_x = [];
        let g_pointcloud_y = [];
        const g_img = new Image();

        // 初始化画布
        var gg_background_canvas = document.getElementById("backgrounds");
        var gg_map_canvas = document.getElementById("back");
        var gg_robot_canvas = document.getElementById("mid");
        var gg_pcl_canvas = document.getElementById("front");

        g_background_canvas = gg_background_canvas.getContext('2d'); // 背景画布
        g_map_canvas = gg_map_canvas.getContext('2d'); // 地图画布
        g_robot_canvas = gg_robot_canvas.getContext('2d'); // 机器人画布
        g_pcl_canvas = gg_pcl_canvas.getContext('2d'); // 点云画布

        myresize();

        // 通用get请求
        function get_map_data(theUrl)
        {
            var xmlHttp = new XMLHttpRequest();
            xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
            xmlHttp.send( null );
            // json_data = JSON.parse(xmlHttp.responseText);
            return JSON.parse(xmlHttp.responseText);
        }

        //获取窗口宽度
        function w() {
            if (window.innerWidth) {  //兼容DOM
                return window.innerWidth;
            }
            if ((document.body) && (document.body.clientWidth)){  //兼容IE
                return document.body.clientWidth;
            }
        }
        //获取窗口高度
        function h() {
            if (window.innerHeight) {  //兼容DOM
                return window.innerHeight;
            }
            if ((document.body) && (document.body.clientHeight)) { //兼容IE
                return document.body.clientHeight;
            }
        }
        // 绘制机器人坐标及实时地图、点云
        function draw_slam_map() {

            // 请求slam实时数据

            // g_get_slam_data = JSON.parse( get_map_data(g_get_slam_map_url) );
            g_get_slam_data = get_map_data(g_get_slam_map_url);
            // 清除背景
            clear("background");
            if ( g_get_slam_data.code == 0 ) {
                g_slam_flag = true;
                draw("background");
            }
            else {
                g_slam_flag = false;
                draw("no_slam");
                return false;
            }
            // console.info(g_get_slam_data);


            // 给地图全局变量
            g_map_data = g_get_slam_data.data.AGVMap.mapData
            clear("map");
            draw("map");

            // 机器人坐标
            g_robot_position.x = ( - g_get_slam_data.data.AGVMap.originX + g_get_slam_data.data.robotPose.x) / g_get_slam_data.data.AGVMap.resolution
            g_robot_position.y = ( g_get_slam_data.data.AGVMap.physicsHeight + g_get_slam_data.data.AGVMap.originY - g_get_slam_data.data.robotPose.y ) / g_get_slam_data.data.AGVMap.resolution
            g_robot_position.theta = g_get_slam_data.data.robotPose.theta

            if ( g_get_slam_data.data.robotPose.x != 0 && g_get_slam_data.data.robotPose.y != 0 ) {
                clear("robot");
                draw("robot");
            }

            // 绘制点云地图
            // 绘制点云
            // 请求pointcloud实时数据
            var point_cloud_json = get_map_data(g_get_pointcloud_url);
            g_countryList = point_cloud_json.data.pointCloud;
            if ( g_countryList.length > 0 ) {
                g_pointcloud_x = []
                g_pointcloud_y = []
                for ( var i = 0; i < g_countryList.length; i++ ) {
                    var pix_x = ( - g_get_slam_data.data.AGVMap.originX + g_countryList[i]["x"]) / g_get_slam_data.data.AGVMap.resolution;
                    var pix_y = ( g_get_slam_data.data.AGVMap.physicsHeight + g_get_slam_data.data.AGVMap.originY - g_countryList[i]["y"] ) / g_get_slam_data.data.AGVMap.resolution;
                    // 填充全局容器
                    g_pointcloud_x.push(pix_x);
                    g_pointcloud_y.push(pix_y);
                }

                // 清除并重绘
                clear("pointcloud");
                draw("pointcloud");
            }
            // 加载地图->触发回调事件
            g_img.src = g_get_slam_data.data.AGVMap.mapData

        }

        //ctx指定画布,stepX是线与线x间距 stepY是线与线y间距 color是线的颜色 lineWidth是线的宽度
        function drawGrid(ctx, stepX, stepY, color, lineWidth){
        // // 设置绘制颜色
            ctx.strokeStyle = color;
            // 创建垂直格网线路径
            for(let i = stepX; i < canvas.width; i += stepX){
            // 设置绘制线段的宽度
            ctx.lineWidth = lineWidth;
            //开启路径
            ctx.beginPath()

            //笔触的位置-moveTo经常是画一些不连续的线
            ctx.moveTo(i, 0);
            //绘制一条从当前位置到指定x以及y位置的直线。
            ctx.lineTo(i,canvas.height);
            ctx.stroke()
            }
            // 创建水平格网线路径
            for(let j = stepY; j < canvas.height; j += stepY){
                // 设置绘制线段的宽度
            ctx.lineWidth = lineWidth;
                //开启路径
                ctx.beginPath()
                ctx.moveTo(0, j);
                ctx.lineTo(canvas.width, j);
                ctx.stroke()
            }
        }

        function draw(type) {
            if (type == "map"){
                g_map_canvas.drawImage(g_img, g_offset.x, g_offset.y);
            }
            if (type == "robot"){
                // 点位置
                g_robot_canvas.save();
                g_robot_canvas.beginPath();
                // 旋转到正确角度
                //g_robot_canvas.translate(g_size.x, g_size.y);
                //g_robot_canvas.rotate(g_robot_position.theta);
                //g_robot_canvas.translate(-g_size.x, -g_size.y);

                g_robot_canvas.rect(g_offset.x + g_robot_position.x, g_offset.y + g_robot_position.y, 10, 10);
                g_robot_canvas.strokeStyle = 'blue';
                g_robot_canvas.lineWidth = 0;
                g_robot_canvas.fillStyle = 'blue';
                g_robot_canvas.fill();
                g_robot_canvas.stroke();
                g_robot_canvas.closePath();

            }

            if (type == "pointcloud") {

                g_pcl_canvas.save();
                g_pcl_canvas.beginPath();
                for ( var i=0; i < g_pointcloud_x.length; i++ )
                {
                    g_pcl_canvas.rect(g_offset.x + g_pointcloud_x[i], g_offset.y + g_pointcloud_y[i], 1, 1);
                    g_pcl_canvas.strokeStyle = 'red';
                    g_pcl_canvas.lineWidth = 0;
                    g_pcl_canvas.fillStyle = 'red';
                    g_pcl_canvas.fill();
                    g_pcl_canvas.stroke();

                }
                g_pcl_canvas.closePath();
            }

            if (type == "background") {
                //调用封装好的表格工具
                drawGrid(g_background_canvas, 20, 20, '#ffffff', 0.5);
            }


            if (type == "no_slam") {
                clear("map");
                clear("robot");
                clear("pointcloud");
                g_background_canvas.font="50px serif";
                g_background_canvas.fillStyle="#ff0000";
                g_background_canvas.fillText("slam模式未就绪！", 0, 50);
            }


            if (type == "no_map") {
                clear("map");
                clear("robot");
                clear("pointcloud");
                g_background_canvas.font="50px serif";
                g_background_canvas.fillStyle="#ff0000";
                g_background_canvas.fillText("定位模式未就绪或不存在地图！", 0, 50);
            }

        }

        function clear_all() {
            clear("background");
            clear("map");
            clear("robot");
            clear("pointcloud");
        }

        function draw_all() {
            draw("background");
            if ( g_slam_flag ) {
                draw("map");
                draw("robot");
                draw("pointcloud");
            }
        }

        // 清除画布
        function clear(type) {
            if (type == "map"){
                g_map_canvas.beginPath();
                g_map_canvas.clearRect(0, 0, canvas.width, canvas.height);
                g_map_canvas.stroke();
            }
            if (type == "robot"){
                g_robot_canvas.beginPath();
                g_robot_canvas.clearRect(0, 0, canvas.width, canvas.height);
                g_robot_canvas.stroke();
            }

            if (type == "pointcloud") {
                g_pcl_canvas.beginPath();
                g_pcl_canvas.clearRect(0, 0, canvas.width, canvas.height);
                g_pcl_canvas.stroke();
            }

            if (type == "background") {
                g_background_canvas.beginPath();
                g_background_canvas.clearRect(0, 0, canvas.width, canvas.height);
                g_background_canvas.stroke();
            }

        }

        function myresize(e) {
            canvas.setAttribute("width", w()*0.7)
            canvas.setAttribute("height", h()*1.0)
            gg_map_canvas.setAttribute("width", w()*0.7)
            gg_map_canvas.setAttribute("height", h()*1.0)
            gg_robot_canvas.setAttribute("width", w()*0.7)
            gg_robot_canvas.setAttribute("height", h()*1.0)
            gg_pcl_canvas.setAttribute("width", w()*0.7)
            gg_pcl_canvas.setAttribute("height", h()*1.0)
            gg_background_canvas.setAttribute("width", w()*0.7)
            gg_background_canvas.setAttribute("height", h()*1.0)

            // console.log("窗口尺寸改变了！")
            // console.log(w())
            // console.log(h())
        }

        function re_draw_all() {
            clear_all();
            draw_all();
        }

        // 监听各种事件
        function listen_event() {
            // 记录鼠标按下时，画布本身的偏移量
            var click_offset = {
                x: 0,
                y: 0
            }

            // 记录鼠标按下的坐标
            var click_position = {
                x: 0,
                y: 0
            }
            var move_flag = false;

            function mymousemove(e) {
                if(!move_flag) return;
                // console.log("move")
                // console.log(e.offsetX)
                // console.log(e.offsetY)
                g_offset.x = click_offset.x + e.offsetX - click_position.x;
                g_offset.y = click_offset.y + e.offsetY - click_position.y;
                // console.log(g_offset)

                setTimeout(re_draw_all, 50) // 防止过高刷新率造成内存不够或浏览器响应不过来
            }
            function myclick(){
                // console.log("我被点了一下！") // 触发条件为点击并松开
            }
            function mydblclick(){
                // console.log("我被点了两下！")
            }
            function mymouseEnter(){
                // console.log("我的鼠标移进来了！")
            }
            function mymouseOut(){
                move_flag = false;
                // console.log("我的鼠标移出去了！")
            }
            function mymousesDown(e){
                move_flag = true;
                click_position.x = e.offsetX
                click_position.y = e.offsetY

                // 保证任何时刻点击后移动的顺畅
                click_offset.x = g_offset.x;
                click_offset.y = g_offset.y;

                // console.log(click_position);
                // console.log("我的鼠标点下去了！")
            }
            function mymouseUp(){
                move_flag = false;
                click_position.x = 0
                click_position.y = 0

                // console.log("我的鼠标松开了！")
            }
            function mywheel(e) {
                console.log(e.deltaY)
                // 放大
                if ( e.deltaY < 0 ) {
                    g_map_canvas.scale(1.1, 1.1);
                    g_pcl_canvas.scale(1.1, 1.1);
                    g_robot_canvas.scale(1.1, 1.1);
                    re_draw_all();
                }
                // 缩小
                else {
                    g_map_canvas.scale(0.9, 0.9);
                    g_pcl_canvas.scale(0.9, 0.9);
                    g_robot_canvas.scale(0.9, 0.9);
                    re_draw_all();

                }

            }

            // 添加事件
            gg_pcl_canvas.addEventListener('mousemove', mymousemove, true);
            gg_pcl_canvas.addEventListener('click', myclick, true);
            gg_pcl_canvas.addEventListener('dblclick', mydblclick, true);
            gg_pcl_canvas.addEventListener('mouseenter', mymouseEnter, true);
            gg_pcl_canvas.addEventListener('mouseout', mymouseOut, true);
            gg_pcl_canvas.addEventListener('mousedown', mymousesDown, true);
            gg_pcl_canvas.addEventListener('mouseup', mymouseUp, true);
            gg_pcl_canvas.addEventListener('wheel', mywheel, true);
            window.addEventListener('resize', myresize, true);
        }

        // 开始建图触发事件
        function on_start_slam() {
            get_map_data("/on_start_slam");
        }

        // 保存建图触发事件
        function on_save_slam() {
            get_map_data("/on_save_slam");
        }

        // 主函数
        function main() {
            // 初始化先一次
            draw_slam_map();
            // 每隔一段时间询问一次，切换则可迅速进入界面
            setInterval(function () {
                // 图片位置
                draw_slam_map();
            }, 2000)

            // 载入时加载
            g_img.onload = function(event) {
                if ( g_timer_id != null )
                {
                    clearTimeout(g_timer_id)
                    g_timer_id = null;
                }
                // 定时器
                g_timer_id = setTimeout(draw_slam_map, 200)
            }

            // 监听鼠标、键盘等事件
            listen_event();
        }

        main();
    </script>
</body>

</html>